﻿// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php

using Nova.Parsing;
using Nova.Rendering;

namespace Nova.CodeDOM
{
    /// <summary>
    /// Represents a section of character data in a documentation comment.
    /// </summary>
    public class DocCDATA : DocComment
    {
        #region /* CONSTRUCTORS */

        /// <summary>
        /// Create a <see cref="DocCDATA"/>.
        /// </summary>
        public DocCDATA(string content)
            : base(content)
        { }

        #endregion

        #region /* PROPERTIES */

        /// <summary>
        /// The XML tag name for the documentation comment.
        /// </summary>
        public override string TagName
        {
            get { return ParseToken; }
        }

        #endregion

        #region /* PARSING */

        /// <summary>
        /// The token used to parse the code object.
        /// </summary>
        public new const string ParseToken = "![CDATA[";

        /// <summary>
        /// The closing token.
        /// </summary>
        public const string ParseTokenClose = "]]>";

        internal static void AddParsePoints()
        {
            Parser.AddDocCommentParseTag(ParseToken, Parse);
        }

        /// <summary>
        /// Parse a <see cref="DocCDATA"/>.
        /// </summary>
        public static new DocCDATA Parse(Parser parser, CodeObject parent, ParseFlags flags)
        {
            return new DocCDATA(parser, parent);
        }

        /// <summary>
        /// Parse a <see cref="DocCDATA"/>.
        /// </summary>
        public DocCDATA(Parser parser, CodeObject parent)
        {
            Parent = parent;
            NewLines = parser.LastToken.NewLines;  // Get any newlines from the '<'
            parser.NextToken(true);                // Move past '![CDATA['
            if (!ParseContent(parser))
            {
                _annotationFlags |= AnnotationFlags.NoEndTag;
                parser.AttachMessage(this, "Start tag '<" + ParseToken + "' without matching end tag!", parser.LastToken);
            }
        }

        protected override bool ParseContent(Parser parser)
        {
            _content = "";

            // Skip if we hit EOF, or the close token, or we've exited the doc comment or got an invalid token type
            if (parser.Token != null && parser.TokenText != ParseTokenClose && (parser.InDocComment || parser.TokenType == TokenType.DocCommentString))
            {
                // Handle comment text
                string text = parser.Token.LeadingWhitespace + parser.TokenText;

                // Add any newlines to the front of the text
                if (parser.Token.NewLines > 0)
                    text = new string('\n', parser.Token.NewLines) + text;

                // If we're at the end of the doc comment, truncate the trailing newline
                if (!parser.InDocComment)
                    text = text.TrimEnd('\n');

                Add(text);
                parser.NextToken(true);  // Move past text
            }

            if (parser.TokenText == ParseTokenClose)
            {
                parser.NextToken(true);  // Move past ']]>'
                return true;
            }

            return false;
        }

        #endregion

        #region /* FORMATTING */

        /// <summary>
        /// True if the code object defaults to starting on a new line.
        /// </summary>
        public override bool IsFirstOnLineDefault
        {
            get { return false; }
        }

        #endregion

        #region /* RENDERING */

        protected override void AsTextStart(CodeWriter writer, RenderFlags flags)
        {
            if (!flags.HasFlag(RenderFlags.Description) || MissingEndTag)
                writer.Write("<" + ParseToken);
        }

        protected override void AsTextContent(CodeWriter writer, RenderFlags flags)
        {
            DocText.AsTextText(writer, GetContentForDisplay(flags), flags | RenderFlags.NoTranslations);
        }

        protected override void AsTextEnd(CodeWriter writer, RenderFlags flags)
        {
            if (!MissingEndTag && !flags.HasFlag(RenderFlags.Description))
                writer.Write(ParseTokenClose);
        }

        #endregion
    }
}
